using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.WindowsAzure.ServiceRuntime;
using IisSite=Microsoft.Web.Administration.Site;
using Microsoft.Web.Administration;

namespace Microsoft.WindowsAzure.Accelerator.Configuration
{
    /// <summary>
    /// The Windows Azure Accelerators engine's service configuration and definition schema. Used
    /// in conjuntion with the base Application definitions to provide the runtime implementation
    /// of the base application requirements.
    /// Ensure that the service and role names match the names as declared in the .cscfg and
    /// .csdef files.
    /// </summary>
    public partial class ServiceAccelerator
    {
        /// <summary>
        /// Gets the runtime accelerator role configuration.
        /// </summary>
        /// <value>The runtime role configuration.</value>
        public AcceleratorRole RuntimeRole
        {
            get
            {
                if (RoleEnvironment.IsAvailable && AcceleratorRole != null && AcceleratorRole.Count > 0)
                {
                    var role = AcceleratorRole.Where(ar => ar.name == RoleEnvironment.CurrentRoleInstance.Role.Name).FirstOrDefault();
                    return role;
                }
                return null;
            }
        }
    }

    /// <summary>
    /// The configuration of an accelerator web role which accepts external requests.
    /// </summary>
    public partial class AcceleratorRole
    {
        public Site this[String index]
        {
            get { { return this.Sites.Protect(sites => sites.Site.Where(site => site.name == index).FirstOrDefault()) ?? null; } }
        }
    } 

    /// <summary>
    /// Specifies a web site or web application that is part of the web role.
    /// </summary>
    public partial class Site
    {
        private const String serviceDefinitionLocation = @"//Sites/Site[@name={0}]";
        public String RoleName { get { return RoleEnvironment.CurrentRoleInstance.Id; } }

        /// <summary>
        /// Gets the IIS web site object corresponding to this definition.
        /// </summary>
        /// <value>The web site.</value>
        public Web.Administration.Site WebSite
        {
            get
            {   using (var sm = new ServerManager())
                {
                    return sm.Sites.Where(site => site.Name.Replace(RoleEnvironment.CurrentRoleInstance.Id + "_", "") == name).FirstOrDefault();
                }
            }
        }
     
        public override void SetApplicationPool()
        {
            base.SetApplicationPool();
        }
    }

    /// <summary>
    /// Specifies a directory name that is mapped to a physical directory on the local and remote server.
    /// </summary>
    public partial class VirtualApplication 
    {
        public virtual void SetApplicationPool()
        {
                       
        }
    }

    /// <summary>
    /// Defines a web application running in IIS.
    /// </summary>
    public partial class VirtualDirectory
    {
        /// <summary>
        /// Gets the virtual applications.
        /// </summary>
        /// <value>The virtual applications.</value>
        public IEnumerable<VirtualApplication> VirtualApplications
        {
            get { return this.Items.OnValid(i => i.OfType<VirtualApplication>()); }
        }

        /// <summary>
        /// Returns all descendant virtual directories and applications.
        /// </summary>
        /// <returns>Descendant virtual directories.</returns>
        public IEnumerable<KeyValuePair<String, VirtualDirectory>> Descendants()
        {
            if (this.Items != null && this.Items.Count > 1)
                foreach(var item in Items)
                { 
                    yield return new KeyValuePair<String, VirtualDirectory>(String.Format("{0}/{1}", name, item.name), item);
                    foreach(var descendant in item.Descendants())
                        yield return descendant;
                }
        }

        /// <summary>
        /// Creates the sites directories.
        /// </summary>
        /// <remarks>
        /// BUGBUG:  (b|rdm)
        /// Mirroring the entire physical structure is not correct.  Virtual directories should retain
        /// their unique physical separation characteristics.  This is a bug.  I need to figure out how
        /// Azure does this and mirror their virtual directory process.
        /// </remarks>
        /// <param name="targetContainer">The target path.</param>
        /// <returns></returns>
        public void CopyPhysicalDirectory(Path targetContainer)
        {
            //i|
            //i|
            //i|
            if (String.IsNullOrEmpty(name))
                throw new ArgumentException(String.Format("Invalid VirtualDirectory name '{0}'.", name));
            Path target = System.IO.Path.Combine(targetContainer, name);

            //i| First, check if we have a reset on the physical directory; 
            //i| if so we need to copy from a new location.)
            if (!String.IsNullOrEmpty(physicalDirectory))
            {
                //i| Source can be absolute or relative to the csdef folder.
                Path source = physicalDirectory;
                if (!source.IsRootPath())
                    source = ServiceManager.Settings.ServiceDefinitionFile.GetFolder().Combine(source);
                if (File.Exists(source))
                    source.CopyPath(target);
                else
                    Trace.TraceError("Unable to find source directory at '{0}'.", source);
            }
        }

        /// <summary>
        /// Copies all virtual directories.
        /// </summary>
        /// <param name="targetContainer">The target path.</param>
        /// <returns></returns>
        public void CopyVirtualDirectories(Path targetContainer)
        {
            //|
            //| Process all child VirtualDirectory / VirtualApplication elements.
            //|
            foreach (var virtualDirectory in Items.OfType<VirtualDirectory>())
            {
                virtualDirectory.CopyPhysicalDirectory(targetContainer);
            }
        }
    } 
}